/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		acleditor load.cpp
 * PURPOSE:		acl -> acl dialog state conversion
 *				included as part of acleditor.cpp
 */

class AclEditorLoad : public AclEditorInit
{
protected:
	AclEditorLoad(AclEditorInitParams const &Init) :
		AclEditorInit(Init)
	{
		if(Init.AclAndState.State & ACL_FLAG_PRESENT)
		{
			PreviousAclState = Init.AclAndState.State;
			LoadAcl(Init.AclAndState);
		}
	}

private:
	BOOL GetColumnBitState(UCHAR i, USHORT aceflags, ACCESS_MASK mask)
	{
		if(i < COL_MASK) //must be an aceflag
			return aceflags >> (i - COL_ACE_FLAGS) & 1;
		else
			return mask >> (i - COL_MASK) & 1;
	}

	void AddBitsRow(USHORT aceflags, ACCESS_MASK mask)
	{
		for(UCHAR i = COL_ACE_FLAGS; i <= COL_MAX_ACE; i++)
		{
			LRESULT LastIndex = RaiseSendMessageListBox(Columns[i].Wnd, LB_ADDSTRING, NULL, (LPARAM)L"");

			RaiseSendMessageListBox(Columns[i].Wnd, LB_SETSEL, GetColumnBitState(i, aceflags, mask), LastIndex);
		}
	}

	void AddCommonAceBitsRow(ACE const *Ace)
	{
		AddBitsRow(Ace->Flags, Ace->Mask);
	}

	void AddSidRows(SID const *sid)
	{
		if(sid)
		{
			auto_szpod<WCHAR> RawName = SidToText(sid);

			RaiseSendMessageListBox(Columns[COL_TSTE_SID].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(RawName.get()));

			USHORT NextIndex = narrowing_cast<USHORT>(RaiseSendMessageListBox(Columns[COL_TSTE_NAME].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(L"")));

			LookupSid(Rows[NextIndex], sid);
		}
		else
		{
			RaiseSendMessageListBox(Columns[COL_TSTE_NAME].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(L""));
			RaiseSendMessageListBox(Columns[COL_TSTE_SID].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(L""));
		}
	}

	void AddObjectRows(ListboxAceRow *Row)
	{
		auto_szpod<WCHAR> Text;

		if(Row->TypeGuid)
		{
			Text = GuidToText(Row->TypeGuid);
			RaiseSendMessageListBox(Columns[COL_OBJ_TYPE].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(Text.get()));
			LookupObjectTypeGuid(Row, *Row->TypeGuid, COL_OBJ_TYPE);
		}
		else
			RaiseSendMessageListBox(Columns[COL_OBJ_TYPE].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(L""));

		if(Row->InhTypeGuid)
		{
			Text = GuidToText(Row->InhTypeGuid);
			RaiseSendMessageListBox(Columns[COL_OBJ_INH_TYPE].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(Text.get()));
			LookupObjectInhTypeGuid(Row, *Row->InhTypeGuid, COL_OBJ_INH_TYPE);
		}
		else
			RaiseSendMessageListBox(Columns[COL_OBJ_INH_TYPE].Wnd, LB_ADDSTRING, NULL, c_cast<LPARAM>(L""));
	}

	void AddAceTypeRow(UCHAR Type)
	{
		if(Type > ACE_TYPE_MAX)
		{
			WCHAR Buff[40];
			_itow_s(Type, Buff, 40, 10);

			RaiseSendMessageListBox(Columns[COL_ACE_TYPE].Wnd, LB_ADDSTRING, 0, reinterpret_cast<ULONG_PTR>(Buff));
		}
		else
			RaiseSendMessageListBox(Columns[COL_ACE_TYPE].Wnd, LB_ADDSTRING, 0, reinterpret_cast<ULONG_PTR>(AceTypeLabels[Type]));
	}

	void AddSourceRow(ACE *Ace)
	{
		if(Ace->Flags & ACE_FLAG_INH_SOURCE_KNOWN)
		{
			if(Ace->Flags & ACE_FLAG_INH_INVALID)
				RaiseSendMessageListBox(Columns[COL_INH_SOURCE].Wnd, LB_ADDSTRING, 0, reinterpret_cast<ULONG_PTR>(L"<Invalid inheritance>"));
			else
			{
				WCHAR Buff[MAX_STRING_CHARS];

				PCWSTR SourceName;

				if(PathParts.get_ct())
					SourceName = PathParts[PathParts.get_ct() > (SIZE_T)Ace->Source + 1 ? PathParts.get_ct() - (Ace->Source + 1) : 0];
				else
					SourceName = L"<null>";

				swprintf_s(Buff, L"%s%s, %hu up", Ace->Flags & ACE_FLAG_INH_SOURCE_MINONLY ? L"near " : L"", SourceName, Ace->Source);

				RaiseSendMessageListBox(Columns[COL_INH_SOURCE].Wnd, LB_ADDSTRING, 0, reinterpret_cast<ULONG_PTR>(Buff));
			}
		}
		else
			RaiseSendMessageListBox(Columns[COL_INH_SOURCE].Wnd, LB_ADDSTRING, 0, reinterpret_cast<ULONG_PTR>(L""));
	}

protected:
	void LoadAcl(ACL_AND_STATE const &AclAndState)
	{
		ACL const *Acl = AclAndState.Acl;

		if(!Acl)
			return;

		WORD ct = Acl->AceCount;
		union //AcePos is incremented while walking contiguous ACE structures
		{
			ULONG_PTR AcePos;
			ACE *Ace;
		};

		AcePos = reinterpret_cast<ULONG_PTR>(Acl) + sizeof(ACL);

		while(ct--)
		{
			auto_refct<ListboxAceRow> lar = new ListboxAceRow(this, Columns, Ace);

			AddDataRow(lar);

			AddAceTypeRow(Ace->Type);

			AddCommonAceBitsRow(Ace);

			AddSourceRow(Ace);

			if(IsStdAce(Ace->Type))
			{
				AddSidRows(Ace->Standard.SidStart);
				AddObjectRows(lar);
			}
			else if(IsObjectAce(Ace->Type))
			{
				union
				{
					ULONG_PTR AcePos2;
					GUID *Guid;
					SID *Sid;
				};

				AcePos2 = reinterpret_cast<ULONG_PTR>(Ace->Object.Body);

				if(Ace->Object.Flags & ACE_OBJECT_TYPE_PRESENT)
				{
					lar->TypeGuid = Guid;
					AcePos2 += sizeof(GUID);
				}

				if(Ace->Object.Flags & ACE_INHERITED_OBJECT_TYPE_PRESENT)
				{
					lar->InhTypeGuid = Guid;
					AcePos2 += sizeof(GUID);
				}

				AddSidRows(Sid);
				AddObjectRows(lar);
				Scroll(); //prevent scroll drift while adding items
			}
			else //filler rows need to be added in any case
			{
				AddObjectRows(lar);
				AddSidRows(NULL);
			}

			AcePos += Ace->Size;
		}

		//Acl flags
		if(AclAndState.State & ACL_FLAG_DEFAULTED)
			SendMessage(Toolbar, TB_CHECKBUTTON, TbDefaulted, MAKELONG(TRUE, 0));
		
		if(AclAndState.State & ACL_FLAG_PROTECTED)
			SendMessage(Toolbar, TB_CHECKBUTTON, TbProtected, MAKELONG(TRUE, 0));
		
		if(AclAndState.State & ACL_FLAG_AUTO_INHERIT)
			SendMessage(Toolbar, TB_CHECKBUTTON, TbAutoInherit, MAKELONG(TRUE, 0));
		
		if(AclAndState.State & ACL_FLAG_MERGE_UNPROTECT)
			SendMessage(Toolbar, TB_CHECKBUTTON, TbMergeUnprotect, MAKELONG(TRUE, 0));

		//Acl merge mode range check
		if((AclAndState.State & ACL_MERGE_MODE_BITS) > ACL_MERGE_MODE_MAX)
			RaiseWin32Error(ERROR_INVALID_ACL);

		//Acl merge mode
		SendMessage(Toolbar, TB_CHECKBUTTON, ((AclAndState.State & ACL_MERGE_MODE_BITS) >> ACL_MERGE_MODE_SHIFT) + TbMergeStart, TRUE);

		//ensure that a row is always selected, when one exists
		if(Acl->AceCount > 0)
			SyncAceSelection(0);
	}
};